﻿package com.toncen.samepms.basic.action;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import ognl.Ognl;
import ognl.OgnlContext;

import org.apache.struts2.ServletActionContext;

import sun.misc.BASE64Decoder;
import sun.misc.CharacterDecoder;

import com.toncen.samepms.basic.dao.OrganizationDao;
import com.toncen.samepms.basic.dao.UserDao;
import com.toncen.samepms.basic.domain.Organization;
import com.toncen.samepms.basic.domain.User;
import com.toncen.samepms.common.AbstractDatabaseAction;
import com.toncen.samepms.common.ComitConstant;
import com.toncen.samepms.interceptor.Begin;
import com.toncen.samepms.interceptor.End;
import com.toncen.samepms.interceptor.In;
import com.toncen.samepms.interceptor.Out;
import com.toncen.samepms.interceptor.Transaction;
import com.toncen.samepms.system.dao.FunctionPermissionDao;
import com.toncen.samepms.system.dao.ModuleDao;
import com.toncen.samepms.system.dao.RoleDao;
import com.toncen.samepms.system.domain.Advice;
import com.toncen.samepms.system.domain.Module;
import com.toncen.samepms.system.domain.Role;
import com.opensymphony.xwork2.ActionContext;
import com.sky.common.sql.JavaSQLUtils;
import com.sky.common.string.StringUtils;

/**
 * 描述：用户表BASIC_USER的action文件
 * 
 * @author tch
 * 
 */
public class UserAction<U, D> extends AbstractDatabaseAction<User, UserDao<User>> {
	/**
	 * 序列号
	 */
	private static final long serialVersionUID = 1331547659534L;

	/**
	 * 可以选择的角色列表
	 */
	@In
	@Out
	private List<Role> roleList = new ArrayList<Role>();

	/**
	 * 选中的多个角色
	 */
	@In
	@Out
	private Long[] rolesChecked;

	/**
	 * 选中的单个角色
	 */
	@In
	@Out
	private Long roleChecked;

	/**
	 * 是否修改个人信息
	 */
	@In
	@Out
	private boolean modifySelf = false;

	/**
	 * 找回密码发送方式
	 */
	@In
	@Out
	private int forgotSendType = 1;

	/**
	 * 用户名和密码是否加密
	 */
	@In
	@Out
	private boolean encryptData = true;

	public UserAction() throws Exception {
		super();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#prepareOnDoList()
	 */
	@Override
	public void prepareOnDoList() throws Exception {
		super.prepareOnDoList();
		ServletActionContext.getRequest().setAttribute("roleIds", getPermissions(Role.class.getSimpleName(), getCurrentUser()));// 设置角色动态过滤参数
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#prepareOnDoEdit()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void prepareOnDoEdit() throws Exception {
		super.prepareOnDoEdit();
		getDomain().setOrganization(new OrganizationDao<Organization>().find(getDomain().getOrganization()));
		setRoleList((List) getPermissionList(Role.class.getSimpleName(), getCurrentUser()));

		List<Role> userRoles = getDomain().getRoles();
		Long[] roles = new Long[userRoles.size()];
		for (int i = 0; i < userRoles.size(); i++) {
			if (userRoles.get(i) != null) {
				roles[i] = userRoles.get(i).getId();// 初始化多个角色
				setRoleChecked(userRoles.get(i).getId());// 初始化单个选中的
			}
		}
		setRolesChecked(roles);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#prepareOnDoNew()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void prepareOnDoNew() throws Exception {
		super.prepareOnDoNew();
		getDomain().setOrganization(getCurrentOrganization());
		getDomain().setOrganization(new OrganizationDao<Organization>().find(getDomain().getOrganization()));
		setRoleList((List) getPermissionList(Role.class.getSimpleName(), getCurrentUser()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#prepareOnDoView()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void prepareOnDoView() throws Exception {
		super.prepareOnDoView();
		getDomain().setOrganization(new OrganizationDao<Organization>().find(getDomain().getOrganization()));
		setRoleList((List) getPermissionList(Role.class.getSimpleName(), getCurrentUser()));

		List<Role> userRoles = getDomain().getRoles();
		Long[] roles = new Long[userRoles.size()];
		for (int i = 0; i < userRoles.size(); i++) {
			if (userRoles.get(i) != null) {
				roles[i] = userRoles.get(i).getId();// 初始化多个角色
				setRoleChecked(userRoles.get(i).getId());// 初始化单个选中的
			}
		}
		setRolesChecked(roles);
	}

	@Override
	public void prepareOnDoSave() throws Exception {
		super.prepareOnDoSave();
		// 验证帐号是否存在
		List<User> users = getDao().getByAccount(getDomain().getAccount());
		for(User user : users){
			if (user.getAccount().equals(getDomain().getAccount())&&getDomain().getId()==0) {
				throw new Exception("抱歉：帐号【" + getDomain().getAccount() + "】已经被使用，请使用其它帐号！");
			}
		}
		List<Role> userRoles = new ArrayList<Role>();
		if ("1".equalsIgnoreCase(getConfigValue("enable_multiple_role"))) {// 启用多角色
			if (rolesChecked != null && rolesChecked.length != 0) {// 多个角色
				for (int i = 0; i < rolesChecked.length; i++) {
					Role role = new Role();
					role.setId(rolesChecked[i]);
					userRoles.add(role);
				}
			} else {
				throw new Exception("用户角色必须选取，请选择！");
			}
		} else {
			if (roleChecked != null && roleChecked != 0) {// 单个角色
				Role role = new Role();
				role.setId(roleChecked);
				userRoles.add(role);
			} else {
				throw new Exception("用户角色必须选取，请选择！");
			}
		}
		getDomain().setRoles(userRoles);
	}

	@Override
	public void prepareOnDoChanges() throws Exception {
		super.prepareOnDoChanges();
	}

	public void setRoleList(List<Role> roleList) {
		this.roleList = roleList;
	}

	public List<Role> getRoleList() {
		return roleList;
	}

	public void setRolesChecked(Long[] rolesChecked) {
		this.rolesChecked = rolesChecked;
	}

	public Long[] getRolesChecked() {
		return rolesChecked;
	}

	/**
	 * @return the roleChecked
	 */
	public Long getRoleChecked() {
		return roleChecked;
	}

	/**
	 * @param roleChecked
	 *            the roleChecked to set
	 */
	public void setRoleChecked(Long roleChecked) {
		this.roleChecked = roleChecked;
	}

	/**
	 * @return the modifySelf
	 */
	public boolean isModifySelf() {
		return modifySelf;
	}

	/**
	 * @param modifySelf
	 *            the modifySelf to set
	 */
	public void setModifySelf(boolean modifySelf) {
		this.modifySelf = modifySelf;
	}

	public int getForgotSendType() {
		return forgotSendType;
	}

	public void setForgotSendType(int forgotSendType) {
		this.forgotSendType = forgotSendType;
	}

	public boolean isEncryptData() {
		return encryptData;
	}

	public void setEncryptData(boolean encryptData) {
		this.encryptData = encryptData;
	}

	/**
	 * 注册
	 * 
	 * @return
	 * @throws Exception
	 */
	@Begin
	public String onDoRegister() throws Exception {
		setRoleList(new RoleDao().getAllByRegisterable(1));
		return SUCCESS;
	}

	/**
	 * 提交
	 * 
	 * @return
	 * @throws Exception
	 */
	@End
	@Transaction
	public String onDoSubmit() throws Exception {
		validateVerification();
		this.prepareOnDoSave();
		return this.onDoSave();
	}

	@Begin
	public String onDoForgot() throws Exception {
		return SUCCESS;
	}

	@End
	@Transaction
	public String onDoSend() throws Exception {
		validateVerification();
		List<User> forgots = getDao().getForgotUser(getDomain());
		if (forgots.size() == 0) {// 没有找到
			throw new Exception("没有找到任何符合条件的用户...");
		} else if (forgots.size() == 1) {// 找到唯一一个
			Set<User> toUsers = new HashSet<User>();
			toUsers.addAll(forgots);
			OgnlContext ognlContext = (OgnlContext) Ognl.createDefaultContext(null);
			String subject = getConfigValue("forgot_subject");
			String content = getConfigValue("forgot_content");
			subject = Advice.getConfiguration(ognlContext, forgots.get(0), subject);
			content = Advice.getConfiguration(ognlContext, forgots.get(0), content);
			Advice advice = new Advice();
			advice.setDefaultMode(this.getForgotSendType());
			User fromUser = null;
			advice.send(fromUser, toUsers, subject, content);
		} else {// 找到多个
			List users = JavaSQLUtils.execute(forgots, "select name from " + User.class.getName() + " order by name ");
			throw new Exception("找到【" + forgots.size() + "】个符合条件的用户" + users + "...");
		}
		return SUCCESS;
	}

	/**
	 * 登录
	 * 
	 * @return
	 * @throws Exception
	 */
	public String onDoLogin() throws Exception {
		ActionContext.getContext().getSession().remove(ComitConstant.USER_SESSION_ATTRIBUTE);// 将当前用户从session移除
		ActionContext.getContext().getSession().remove(MODULE_SESSION_ATTRIBUTE);// 将当前用户功能权限从session移除
		if (StringUtils.isEmpty(getDomain().getAccount())) {
			throw new Exception("帐号不能为空，请输入！");
		}
		if (StringUtils.isEmpty(getDomain().getOriginalPassword())) {
			throw new Exception("密码不能为空，请输入！");
		}
		if (encryptData) {// 用户名和密码加密
			CharacterDecoder characterDecoder = new BASE64Decoder();
			getDomain().setAccount(new String(characterDecoder.decodeBuffer(getDomain().getAccount())));
			getDomain().setOriginalPassword(new String(characterDecoder.decodeBuffer(getDomain().getOriginalPassword())));
		}
		List<User> users = null;
		try {
			users = getDao().getByAccount(getDomain().getAccount());
		} catch (Exception e) {
			throw new Exception("用户名、密码不正确，请重新输入！(注意：用户名、密码区分大小写，请确认是否正确)");
		}
		User user = null;
		if (users.size() == 1) {
			user = users.get(0);
		} else if (users.size() > 1) {// 帐号重复
			throw new Exception("帐号[" + getDomain().getAccount() + "]重复，请与系统管理员联系!");
		}
		if (user == null) {
			throw new Exception("用户名、密码不正确，请重新输入！(注意：用户名、密码区分大小写，请确认是否正确)");
		} else if (user.getOrganization() != null && user.getOrganization().getState() != 1) {
			throw new Exception("帐号[" + getDomain().getAccount() + "]所在单位[" + user.getOrganization().getName() + "]未激活，请激活单位后再登录！");
		} else if (user.getState() != 1) {
			throw new Exception("帐号[" + getDomain().getAccount() + "]未激活，请激活后再登录！");
		} else if (!user.getOriginalPassword().equals(getDomain().getOriginalPassword())) {
			throw new Exception("用户名、密码不正确，请重新输入！");
		} else {
			if ("1".equalsIgnoreCase(getConfigValue("enable_verification"))) {// 启用验证码
				validateVerification();
			}
			ActionContext.getContext().getSession().put(ComitConstant.USER_SESSION_ATTRIBUTE, user);// 将当前用户存入session中
			synchronized (LOCK) {
				initializePermission(user);// 初始化功能权限
			}
		}
		return SUCCESS;
	}

	private static final Object LOCK = new Object();

	/**
	 * 注销
	 * 
	 * @return
	 * @throws Exception
	 */
	public String onDoLogout() throws Exception {
		ActionContext.getContext().getSession().remove(ComitConstant.USER_SESSION_ATTRIBUTE);// 将当前用户从session移除
		ActionContext.getContext().getSession().remove(MODULE_SESSION_ATTRIBUTE);// 将当前用户功能权限从session移除
		return SUCCESS;
	}

	/**
	 * 判断是否已经登录
	 * 
	 * @return
	 * @throws Exception
	 */
	public String onDoIsLogin() throws Exception {
		User user = (User) ActionContext.getContext().getSession().get(ComitConstant.USER_SESSION_ATTRIBUTE);// 从session中获取当前用户
		if (user != null && user.getName() != null && !user.getName().equals("")) {
			return SUCCESS;
		} else
			return "login";
	}

	/**
	 * 功能权限缓存
	 */
	private static Map<String, List<Module>> CACHE_FUNCTIONPERMISSIONS = new LinkedHashMap<String, List<Module>>();

	/**
	 * 初始化功能权限
	 * 
	 * @param user
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private void initializePermission(User user) throws Exception {
		String permissionKey = user.getPermissionKey();// 缓存权限key:组织+用户+角色组合
		List<Module> roots = CACHE_FUNCTIONPERMISSIONS.get(permissionKey);
		if (roots == null || ComitConstant.isDeveloperMode()) {
			FunctionPermissionDao functionPermissionDao = new FunctionPermissionDao();
			Set<Long> moduleIds = functionPermissionDao.getModuleFunctionPermissions(user);// 获取功能权限
			ModuleDao moduleDao = new ModuleDao();
			roots = moduleDao.getAllRootModule();// 获取一级模块
			removesUselessModule(roots, moduleIds);// 移除没有权限的模块
			String size = getConfigValue("cache_functionpermission_size");// 功能权限缓存大小
			if (CACHE_FUNCTIONPERMISSIONS.size() >= Integer.parseInt(size)) {// 超出最多缓存限制，则移除最近最少使用的
				CACHE_FUNCTIONPERMISSIONS.remove(CACHE_FUNCTIONPERMISSIONS.keySet().iterator().next());// 移除第一个
			}
			CACHE_FUNCTIONPERMISSIONS.put(permissionKey, roots);
		}
		ActionContext.getContext().getSession().put(MODULE_SESSION_ATTRIBUTE, roots);// 放入session中
	}

	/**
	 * 清除缓存权限
	 * 
	 */
	public static void clearCachePermissions() {
		CACHE_FUNCTIONPERMISSIONS.clear();
	}

	/**
	 * 移除没有权限的模块
	 * 
	 * @param modules
	 * @param moduleIds
	 */
	private void removesUselessModule(List<Module> modules, Set<Long> moduleIds) {
		Iterator<Module> iterator = modules.iterator();
		Module module = null;
		boolean isLeft;
		while (iterator.hasNext()) {
			module = iterator.next();
			isLeft = module.getChilds() == null || module.getChilds().size() == 0;
			removesUselessModule(module.getChilds(), moduleIds);// 递归移除没有权限的模块
			if (!moduleIds.contains(module.getId())) {// 不在权限里面
				if (module.getChilds().size() == 0) {// 全部下级模块都没有，则移除掉
					iterator.remove();
					iterator = modules.iterator();
				}
			} else if (!isLeft) {// 分支节点
				if (module.getChilds().size() == 0) {// 全部下级模块都没有，则移除掉
					iterator.remove();
					iterator = modules.iterator();
				}
			}
		}
	}
}
